﻿using Levfier.Proccessors.Parameters;
using System;

namespace Levfier.Proccessors.Clippers
{
    /// <summary>
    /// ミドルクリップ
    /// ソフトクリップとハードクリップのミックス
    /// </summary>
    [Serializable]
    public class MiddleClipper : Proccessor
    {
        /// <summary>
        /// ゲイン
        /// </summary>
        private ProccessParameter gainParam;

        /// <summary>
        /// 歪のゲイン2
        /// </summary>
        private ProccessParameter hardnessParam;

        /// <summary>
        /// soft : hardのミックス比率
        /// </summary>
        private ProccessParameter mixRateParam;

        /// <summary>
        /// 入力を歪ませる（ミドル）する
        /// </summary>
        /// <param name="input">入力</param>
        /// <param name="output">出力</param>
        protected override void InnerProccess(double[] inputBuffer, double[] outputBuffer)
        {
            //パラメータを取り出す
            double gain = ProccessParameter.ConvertDBToValue(gainParam.Value);
            double logTemp = Math.Log(this.hardnessParam.Value);
            double mixRate = this.mixRateParam.Value;
            double tempSoft = 0.0d;
            double tempHard = 0.0d;

            //計算
            for (int i = 0; i < inputBuffer.Length; i++)
            {
                tempSoft = 2.0d / (1.0d + Math.Exp(logTemp * inputBuffer[i] * -gain)) - 1.0d;
                tempHard = gain * inputBuffer[i];

                if (tempHard > 1.0d)
                {
                    tempHard = 1.0d;
                }
                else if(tempHard < -1.0d)
                {
                    tempHard = -1.0d;
                }

                //ソフト：ハードのミックス
                outputBuffer[i] = (1.0d - mixRate) * tempSoft + mixRate * tempHard;
            }
        }

        /// <summary>
        /// パラメータを初期化する
        /// </summary>
        protected override void InitParameters()
        {
            //ゲイン
            this.gainParam = new ProccessParameter();
            this.gainParam.Name = "Gain[dB]";
            this.gainParam.Value = 0.0d;
            this.gainParam.MaxValue = 100.0d;
            this.gainParam.MinValue = -100.0d;
            this.gainParam.Step = 1.0d;
            this.parameters.Add(this.gainParam.Name, this.gainParam);

            //尖りに関する値
            this.hardnessParam = new ProccessParameter();
            this.hardnessParam.Name = "Hardness";
            this.hardnessParam.Value = 5.0d;
            this.hardnessParam.MaxValue = 10.0d;
            this.hardnessParam.MinValue = 1.0d;
            this.hardnessParam.Step = 0.1d;
            this.parameters.Add(this.hardnessParam.Name, this.hardnessParam);

            //ハード：ソフトのミックス比率 線形性
            this.mixRateParam = new ProccessParameter();
            this.mixRateParam.Name = "Linearity";
            this.mixRateParam.Value = 0.5d;
            this.mixRateParam.MaxValue = 1.0d;
            this.mixRateParam.MinValue = 0.0d;
            this.mixRateParam.Step = 0.05f;
            this.parameters.Add(this.mixRateParam.Name, this.mixRateParam);
        }
    }
}
